using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.IO;
using SlimDX;
using SlimDX.Direct3D9;

namespace TileGert
{
  /// <summary>
  /// This class loads the content from the game directory structure.
  /// All loading is lazy. Content that is loaded once will be cached
  /// until Clear method is called.
  /// </summary>
  public class GertContent
  {
    private Dictionary<string, Texture> fTextures = new Dictionary<string, Texture>();
    //TODO: Animated Sprites
    //TODO: Sounds

    private string _baseDirectory = "Content";
    private GertGame _game = null;

    /// <summary>
    /// Creates a new content manager and loads default tilegert content.
    /// </summary>
    /// <param name="game">The game the content is assigned to.</param>
    public GertContent(GertGame game)
    {
      _game = game;

      //Load the default graphics
      fTextures.Add("tilegert_error", Texture.FromStream(_game.Renderer.D3DDevice, GetType().Assembly.GetManifestResourceStream("TileGert.error.png")));
      fTextures.Add("tilegert_logo", Texture.FromStream(_game.Renderer.D3DDevice, GetType().Assembly.GetManifestResourceStream("TileGert.logo.png")));
      fTextures.Add("tilegert_gridtile", Texture.FromStream(_game.Renderer.D3DDevice, GetType().Assembly.GetManifestResourceStream("TileGert.grid.png")));
      fTextures.Add("tilegert_pixel", Texture.FromStream(_game.Renderer.D3DDevice, GetType().Assembly.GetManifestResourceStream("TileGert.pixel.png")));
      fTextures.Add("tilegert_3x3", Texture.FromStream(_game.Renderer.D3DDevice, GetType().Assembly.GetManifestResourceStream("TileGert.3x3.png")));
    }

    /// <summary>
    /// Loads the texture with the given name from hard disk.
    /// </summary>
    /// <param name="name">The name of the Texture without extension.</param>
    /// <returns></returns>
    private bool LoadTexture(string name)
    {
      string baseDir = _baseDirectory.Trim().Length == 0 ? "" : "\\" + _baseDirectory;
      string filePath = Application.StartupPath + baseDir + "\\Textures\\" + name + ".png";
      if (File.Exists(filePath))
      {
        fTextures.Add(name, Texture.FromFile(_game.Renderer.D3DDevice, filePath));
        return true;
      }
      else
      {
        _game.Logger.LogLine("The texture \"" + name + "\" does not exist!", 1);
        return false;
      }
    }

    /// <summary>
    /// Gets the cache for the given type of assets.
    /// </summary>
    /// <typeparam name="T">The type of assets.</typeparam>
    /// <returns>The cache for the given type of assets. If there is no cache for this,
    /// type null is returned.</returns>
    private Dictionary<string, T> GetCacheForType<T>() where T : Texture //AnimatedSprite, Sound
    {
      if (typeof(T) == typeof(Texture))
        return fTextures as Dictionary<string, T>;

      return null;
    }

    /// <summary>
    /// Gets the asset with the given name. If the asset was not loaded right now,
    /// it is tried to be loaded from the content directory. An Asset that is once loaded
    /// is cached until the Clear method is called. If the asset can not be loaded null is returned.
    /// </summary>
    /// <typeparam name="T">The type of the return value.</typeparam>
    /// <param name="name">The name of the asset without extension.</param>
    /// <returns>The asset with the given name.</returns>
    public T GetAsset<T>(string name) where T : Texture //AnimatedSprite, Sound
    {
      bool cached = AssetIsCached<T>(name);
      if (!cached)
        cached = CacheAsset<T>(name);
      if (cached)
        return GetCacheForType<T>()[name] as T;

      _game.Logger.LogLine("Error while loading asset \"" + name + "\"", 2);
      return null;
    }

    /// <summary>
    /// Checks if the asset with the given name is already cached.
    /// </summary>
    /// <typeparam name="T">The type of the asset.</typeparam>
    /// <param name="name">The name of the asset without extension.</param>
    /// <returns>True if the asset is already cached, else false.</returns>
    public bool AssetIsCached<T>(string name) where T : Texture //AnimatedSprite, Sound
    {
      return GetCacheForType<T>().ContainsKey(name);
    }

    /// <summary>
    /// Loads an asset from hard disk an adds caches it.
    /// If an asset with the given name is already cached, it is not reloaded.
    /// </summary>
    /// <typeparam name="T">The type of the asset.</typeparam>
    /// <param name="name">The name of the asset without extension.</param>
    /// <returns>True if the asset was loaded from harddisk, else false.</returns>
    public bool CacheAsset<T>(string name) where T : Texture //AnimatedSprite, Sound
    {
      if (!AssetIsCached<T>(name))
      {
        if (typeof(T) == typeof(Texture))
          return LoadTexture(name);
      }

      return false;
    }

    /// <summary>
    /// The base directory where the content lies. The default is "Content".
    /// This is the name of the directory, not the path to it. The given
    /// directory has be in the same directory the executable is.
    /// </summary>
    public string BaseDirectory
    {
      get { return _baseDirectory; }
      set { _baseDirectory = value; }
    }

  }
}
